import { readFileSync } from "fs";
import { task_nominal_to_symbolic, parse_abs_type } from "./parsing";

export enum TypeSchemaType {
  Void = 'Void',
  Int = 'Int',
  Float = 'Float',
  Str = 'Str',
  Bool = 'Bool',
  Json = 'Json',
  List = 'List',
  Map = 'Map',
  Tuple = 'Tuple',
  Opt = 'Opt',
  DataType = 'DataType'
}

export class TypeSchema {
  constructor(
    public type: TypeSchemaType,
    public element?: TypeSchema,
    public key?: TypeSchema,
    public value?: TypeSchema,
    public elements?: TypeSchema[],
    public name?: string
  ) {}

  short_str(): string {
    switch (this.type) {
      case TypeSchemaType.Void:
      case TypeSchemaType.Int:
      case TypeSchemaType.Float:
      case TypeSchemaType.Str:
      case TypeSchemaType.Bool:
      case TypeSchemaType.Json:
        return this.type;
      case TypeSchemaType.List:
        return `[${this.element?.short_str()}]`;
      case TypeSchemaType.Map:
        return `{${this.key?.short_str()}, ${this.value?.short_str()}}`;
      case TypeSchemaType.Tuple:
        return `(${this.elements?.map(e => e.short_str()).join(', ')})`;
      case TypeSchemaType.Opt:
        return `?${this.element?.short_str()}`;
      case TypeSchemaType.DataType:
        return this.name || '';
      default:
        return '';
    }
  }
  toString(): string {
    switch (this.type) {
      case TypeSchemaType.Void:
      case TypeSchemaType.Int:
      case TypeSchemaType.Float:
      case TypeSchemaType.Str:
      case TypeSchemaType.Bool:
      case TypeSchemaType.Json:
        return this.type;
      case TypeSchemaType.List:
        return `List<${this.element?.toString()}>`;
      case TypeSchemaType.Map:
        return `Map<${this.key?.toString()}, ${this.value?.toString()}>`;
      case TypeSchemaType.Tuple:
        return `(${this.elements?.map(e => e.toString()).join(', ')})`;
      case TypeSchemaType.Opt:
        return `Option<${this.element?.toString()}>`;
      case TypeSchemaType.DataType:
        return this.name || '';
      default:
        return '';
    }
  }
  static parse(s: string): TypeSchema {
    return parse_abs_type(s);
  }
}

export class ProtocolError extends Error {
    constructor(message: string) {
      super(message);
      this.name = 'ProtocolError';
    }
  }

export type NominalTask = string;
export interface TaskSignature {
  name: string;
  input_type: string;
  output_type: string;
}
export class SymbolicTask {
  constructor(
    public name: string,
    public input_type: TypeSchema,
    public output_type: TypeSchema
  ) {}
  short_str(): string {
    return `${this.name}: ${this.input_type.short_str()} -> ${this.output_type.short_str()}`;
  }
  short_sig(): TaskSignature {
    return {
      name: this.name,
      input_type: this.input_type.short_str(),
      output_type: this.output_type.short_str()
    };
  }
  toString(): string {
    return `${this.name}: ${this.input_type.short_str()} -> ${this.output_type.short_str()}`;
  }
  sig(): TaskSignature {
    return {
      name: this.name,
      input_type: this.input_type.toString(),
      output_type: this.output_type.toString()
    }
  }
  static parse(nominal: string): SymbolicTask {
    let [name, it, ot] = task_nominal_to_symbolic(nominal)
    return new SymbolicTask(name, it, ot)
  }
}

export function qualify(data: any, ts: TypeSchema): boolean {
    if (ts.type === TypeSchemaType.Void && data === null) {
        return true;
    } else if (ts.type === TypeSchemaType.Int && typeof data === 'number' && Number.isInteger(data)) {
        return true;
    } else if (ts.type === TypeSchemaType.Float && typeof data === 'number') {
        return true;
    } else if (ts.type === TypeSchemaType.Str && typeof data === 'string') {
        return true;
    } else if (ts.type === TypeSchemaType.Bool && typeof data === 'boolean') {
        return true;
    } else if (ts.type === TypeSchemaType.Json) {
        return true; // 任何JSON对象都符合Json类型
    } else if (ts.type === TypeSchemaType.List && Array.isArray(data)) {
        return data.every(item => qualify(item, ts.element!));
    } else if (ts.type === TypeSchemaType.Map && typeof data === 'object' && data !== null) {
        return Object.entries(data).every(([key, value]) => 
            qualify(key, ts.key!) && qualify(value, ts.value!)
        );
    } else if (ts.type === TypeSchemaType.Tuple && Array.isArray(data)) {
        if (data.length !== ts.elements!.length) return false;
        return data.every((item, index) => qualify(item, ts.elements![index]));
    } else if (ts.type === TypeSchemaType.Opt) {
        if (data === null || data === undefined) return true;
        return qualify(data, ts.element!);
    } else if (ts.type === TypeSchemaType.DataType) {
        return true; // 暂时不验证
    }
    return false;
}

export type HealthyInfo =
  | { type: 'Healthy' }
  | { type: 'Warn'; message: string }
  | { type: 'Error'; message: string };

export enum TaskStatus {
  Created = 'Created',
  Running = 'Running',
  Completed = 'Completed',
  Failed = 'Failed',
  Stopped = 'Stopped',
  Closed = 'Closed',
  ResultReceived = 'ResultReceived',
  FailedToGetResult = 'FailedToGetResult'
}

function test_qualify() {
    let ts = TypeSchema.parse('List<(Pose, Confidence)>');
    let data = readFileSync("E:/25spring/FYP/fileio/pose_vis_in.json", 'utf-8');
    let poses = JSON.parse(data);
    console.log(qualify(poses, ts));
}

// test_qualify();
